#include <LitStdAfx.h>
#include "LitLight.h"

namespace Lit
{
	Light::Light(const std::string &name, Type type, const Ogre::Vector3& position, const Ogre::Vector3& direction)
		: Movable( MT_LIGHT, name )
	{
		mNameGen = new Ogre::NameGenerator(name.empty()?"Light_":(name+"_"));
		mBaseType = type;
		mBasePosition = position;
		mBaseDirection = direction;
	}
	Light::Light(const Light& rk)
		: Movable( rk )
	{
		mLight = rk.mLight;
		mNameGen = new Ogre::NameGenerator(*rk.mNameGen);
		mBaseType = rk.mBaseType;
		mBasePosition = rk.mBasePosition;
		mBaseDirection = rk.mBaseDirection;
	}
	Light::~Light(void){
		delete mNameGen, mNameGen = NULL;
	}
	std::string Light::typestr() const{return trLightType(type());}

	void Light::replaceLight( Type type, const Ogre::Vector3& position, const Ogre::Vector3& direction ){
		if( !mLight ) return;
		mLight->setType( Ogre::Light::LightTypes(type) );
		mLight->setPosition( position );
		mLight->setDirection( direction );
	}
	
	void Light::create(OgreSceneManagerPtr mgr){
		if( mCreated ) return;
		mMgr = mgr;
		if( mName.empty() )
			mName = mNameGen->generate();
		mLight = mMgr->createLight( mName );
		mNode = mMgr->getRootSceneNode()->createChildSceneNode();
		mNode->attachObject( *mLight );

		mLight->setType( Ogre::Light::LightTypes(mBaseType) );
		mLight->setPosition( mBasePosition );
		mLight->setDirection( mBaseDirection );
		mObject = *mLight;
		mCreated = true;
	}
	void Light::destroy(){
		if( !mCreated ) return;
		mMgr->destroyLight(*mLight);
		mCreated = false;
	}
	void Light::exportAttribs( TiXmlElement * elem )
	{
		if( !mLight ) return;
		elem->SetAttribute( "Name", getName().c_str() );
		elem->SetAttribute( "CastShadows", Ogre::StringConverter::toString( isCastingShadows() ).c_str() );
		elem->SetAttribute( "Position", Ogre::StringConverter::toString(getPosition()).c_str() );
		elem->SetAttribute( "Direction", Ogre::StringConverter::toString(direction()).c_str() );
		elem->SetAttribute( "SpotlightInnerAngle", Ogre::StringConverter::toString(spotlightInnerAngle().valueDegrees()).c_str() );
		elem->SetAttribute( "SpotlightOuterAngle", Ogre::StringConverter::toString(spotlightOuterAngle().valueDegrees()).c_str() );
		elem->SetAttribute( "SpotlightFalloff", Ogre::StringConverter::toString(spotlightFalloff()).c_str() );
		elem->SetAttribute( "SpecularColor", Ogre::StringConverter::toString(diffuseColor()).c_str() );
		elem->SetAttribute( "DiffuseColor", Ogre::StringConverter::toString(specularColor()).c_str() );
		elem->SetAttribute( "AttenuationRange", Ogre::StringConverter::toString(attenuationRange()).c_str() );
		elem->SetAttribute( "AttenuationLinear", Ogre::StringConverter::toString(attenuationLinear()).c_str() );
		elem->SetAttribute( "AttenuationConstant", Ogre::StringConverter::toString(attenuationConstant()).c_str() );
		elem->SetAttribute( "AttenuationQuadratic", Ogre::StringConverter::toString(attenuationQuadratic()).c_str() );
	}
	void Light::importAttribs( TiXmlElement * elem )
	{
		if( !mLight ) return;
		
		const char * shad = elem->Attribute("CastShadows");
		const char * pos = elem->Attribute("Position");
		const char * orient = elem->Attribute("Direction");
		const char * iAgl = elem->Attribute("SpotlightInnerAngle");
		const char * oAgl = elem->Attribute("SpotlightOuterAngle");
		const char * foff = elem->Attribute("SpotlightFalloff");
		const char * diff = elem->Attribute("SpecularColor");
		const char * spec = elem->Attribute("DiffuseColor");
		const char * ar = elem->Attribute("AttenuationRange");
		const char * al = elem->Attribute("AttenuationLinear");
		const char * ac = elem->Attribute("AttenuationConstant");
		const char * aq = elem->Attribute("AttenuationQuadratic");
		
		if( shad ) setCastShadows( Ogre::StringConverter::parseBool( shad ) );
		if( pos ) setPosition( Ogre::StringConverter::parseVector3( pos ) );
		if( orient ) setDirection( Ogre::StringConverter::parseVector3( orient ) );
		if( iAgl ) setSpotlightInnerAngle( Ogre::Degree(Ogre::StringConverter::parseReal(iAgl)) );
		if( oAgl ) setSpotlightOuterAngle( Ogre::Degree(Ogre::StringConverter::parseReal(oAgl)) );
		if( foff ) setSpotlightFalloff( Ogre::StringConverter::parseReal(foff) );
		if( diff ) setDiffuseColor( Ogre::StringConverter::parseColourValue(diff) );
		if( spec ) setSpecularColor( Ogre::StringConverter::parseColourValue(spec) );
		if( ar ) setAttenuationRange( Ogre::StringConverter::parseReal(ar) );
		if( al ) setAttenuationLinear( Ogre::StringConverter::parseReal(al) );
		if( ac ) setAttenuationConstant( Ogre::StringConverter::parseReal(ac) );
		if( aq ) setAttenuationQuadratic( Ogre::StringConverter::parseReal(aq) );
	}
	
	const OgreLightPtr::Ptr Light::operator*() const{ return mLight.get(); }
	const OgreLightPtr::Ptr Light::operator->() const{ return mLight.get(); }
	OgreLightPtr::Ptr Light::operator*(){ return mLight.get(); }
	OgreLightPtr::Ptr Light::operator->(){ return mLight.get(); }
		
	bool Light::isCastingShadows() const{ return mLight->getCastShadows(); }
	void Light::setCastShadows( bool state ){ mLight->setCastShadows( state ); }
		
	Ogre::Real Light::attenuationRange() const{ return mLight->getAttenuationRange(); }
	Ogre::Real Light::attenuationConstant() const{ return mLight->getAttenuationConstant(); }
	Ogre::Real Light::attenuationLinear() const{ return mLight->getAttenuationLinear(); }
	Ogre::Real Light::attenuationQuadratic() const{ return mLight->getAttenuationQuadric(); }

	void Light::setAttenuationRange(Ogre::Real a){ mLight->setAttenuation( a, attenuationConstant(), attenuationLinear(), attenuationQuadratic() ); }
	void Light::setAttenuationConstant(Ogre::Real a){mLight->setAttenuation( attenuationRange(), a, attenuationLinear(), attenuationQuadratic() );}
	void Light::setAttenuationLinear(Ogre::Real a){mLight->setAttenuation( attenuationRange(), attenuationConstant(), a, attenuationQuadratic() );}
	void Light::setAttenuationQuadratic(Ogre::Real a){ mLight->setAttenuation( attenuationRange(), attenuationConstant(), attenuationLinear(), a ); }

		
	Ogre::Vector3 Light::getPosition() const{ return mLight->getPosition(); }
	Ogre::Vector3 Light::direction() const{ return mLight->getDirection(); }
	Ogre::ColourValue Light::diffuseColor() const{ return mLight->getDiffuseColour(); }
	Ogre::ColourValue Light::specularColor() const{ return mLight->getSpecularColour(); }

	void Light::setPosition( const Ogre::Vector3&p ){mLight->setPosition(p); } 
	void Light::setDirection( const Ogre::Vector3&d ){ mLight->setDirection(d); }
	void Light::setDiffuseColor( const Ogre::ColourValue&c ){ mLight->setDiffuseColour( c ); }
	void Light::setSpecularColor( const Ogre::ColourValue&c ){ mLight->setSpecularColour( c ); }
		

	Ogre::Degree Light::spotlightInnerAngle() const{ return mLight->getSpotlightInnerAngle(); }
	Ogre::Degree Light::spotlightOuterAngle() const{ return mLight->getSpotlightOuterAngle(); }
	Ogre::Real Light::spotlightFalloff() const{ return mLight->getSpotlightFalloff(); }

	void Light::setSpotlightInnerAngle( const Ogre::Degree& in  ){mLight->setSpotlightInnerAngle(in);}
	void Light::setSpotlightOuterAngle( const Ogre::Degree& out  ){mLight->setSpotlightOuterAngle(out);}
	void Light::setSpotlightFalloff( Ogre::Real falloff ){mLight->setSpotlightFalloff(falloff);}
	void Light::setSpotlightRange( const Ogre::Degree& in, const Ogre::Degree& out, Ogre::Real falloff ){mLight->setSpotlightRange(in, out, falloff);}
};